package cn.springcloud.fix.demo.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Reactor implements Runnable {

    private final ServerSocketChannel ssc;
    private final Selector selector; // mainReactor用的selector

    public Reactor(int port) throws IOException {
        selector = Selector.open();   // selector
        ssc = ServerSocketChannel.open();  // ServerSocketChannel
        ssc.configureBlocking(false); // 设置ServerSocketChannel为非阻塞
        ssc.socket().bind(new InetSocketAddress(port)); // 在ServerSocketChannel绑定监听端口

        // 所有的都注册到同一个selector上面  这里是启动的时候注册到selector上面，等待连接过来   主线程服务端channel只要接收accept good
        SelectionKey sk = ssc.register(selector, SelectionKey.OP_ACCEPT); // ServerSocketChannel向selector注册一个OP_ACCEPT事件，然后返回该通道的key
        sk.attach(new Acceptor(ssc)); // 给定key一个附加的Acceptor对象
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) { // 在线程被中断前持续运行
            System.out.println("mainReactor waiting for new event on port: " + ssc.socket().getLocalPort() + "...");    // 第二，启动的时候这里打印一句
            try {
                if (selector.select() == 0) // 若沒有事件就绪则不往下执行   启动后这里一定会阻塞 ，有了连接过来之后才放开
                    continue;
            } catch (IOException e) {
                e.printStackTrace();
            }
            Set<SelectionKey> selectedKeys = selector.selectedKeys(); // 取得所有已就绪事件的key集合
            Iterator<SelectionKey> it = selectedKeys.iterator();
            while (it.hasNext()) {
                dispatch(it.next()); // 根据事件的key进行调度
                it.remove();
            }
        }
    }

    private void dispatch(SelectionKey key) {
        Runnable r = (Runnable) (key.attachment()); // 根据事件之key绑定的对象开新线程
        if (r != null) {
            r.run();
        }
    }
}
